package jsoniterx

import (
	"fmt"
	"gitee.com/youbeiwuhuan/taotao-tools4go/base-tools/enumx"
	"gitee.com/youbeiwuhuan/taotao-tools4go/base-tools/tagx"
	"gitee.com/youbeiwuhuan/taotao-tools4go/base-tools/utils/reflectx"
	jsoniter "github.com/json-iterator/go"
	"reflect"
	"unsafe"
)

type EnumEncoder struct {
	enumName             string
	encoder0             jsoniter.ValEncoder // 缓存原来的编码器
	binding              *jsoniter.Binding
	descFieldNameSubffix string // 枚举描述字段的后缀，转json时候除写入原字段外还写入一个新字段，新字段名称=原字段名称+后缀
}

func (en *EnumEncoder) IsEmpty(ptr unsafe.Pointer) bool {
	return reflectx.IsPointerZero(ptr, en.binding.Field.Type().Type1())
}
func (en *EnumEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {

	// 1. 先执行原来逻辑
	en.encoder0.Encode(ptr, stream)

	//t := *(*time.Time)(ptr)

	if ei, ok := enumx.GetEnum2(en.enumName); ok {
		fmt.Println(ei)

		// 2. 写入新逻辑
		stream.WriteRaw(",\"")
		stream.WriteRaw(en.binding.Field.Name() + en.descFieldNameSubffix)
		stream.WriteRaw("\":\"")

		type2 := en.binding.Field.Type()

		var enumValueDesc string

		switch type2.Kind() {
		case reflect.Array, reflect.Struct, reflect.Interface, reflect.Ptr, reflect.Uintptr:
			// 枚举的值不建议是这几种类型，故不处理
			break

		case reflect.String:
			v := *(*string)(ptr)
			enumValueDesc = ei.(enumx.IEnum[string]).GetDesc(v)
			break

		case reflect.Bool:
			v := *(*bool)(ptr)
			enumValueDesc = ei.(enumx.IEnum[bool]).GetDesc(v)

			break
		case reflect.Int:
			v := *(*int)(ptr)
			enu := ei.(enumx.IEnum[int])
			enumValueDesc = enu.GetDesc(v)
			break
		case reflect.Int8:
			v := *(*int8)(ptr)
			enumValueDesc = ei.(enumx.IEnum[int8]).GetDesc(v)
			break
		case reflect.Int16:
			v := *(*int16)(ptr)
			enumValueDesc = ei.(enumx.IEnum[int16]).GetDesc(v)
			break
		case reflect.Int32: // int32 和 rune
			v := *(*int32)(ptr)
			enumValueDesc = ei.(enumx.IEnum[int32]).GetDesc(v)
			break
		case reflect.Int64:
			v := *(*int64)(ptr)
			enumValueDesc = ei.(enumx.IEnum[int64]).GetDesc(v)
			break

		case reflect.Uint:
			v := *(*uint)(ptr)
			enumValueDesc = ei.(enumx.IEnum[uint]).GetDesc(v)
			break
		case reflect.Uint8: // uint8和byte
			v := *(*uint8)(ptr)
			enumValueDesc = ei.(enumx.IEnum[uint8]).GetDesc(v)
			break
		case reflect.Uint16:
			v := *(*uint16)(ptr)
			enumValueDesc = ei.(enumx.IEnum[uint16]).GetDesc(v)
			break
		case reflect.Uint32:
			v := *(*uint32)(ptr)
			enumValueDesc = ei.(enumx.IEnum[uint32]).GetDesc(v)
			break
		case reflect.Uint64:
			v := *(*uint64)(ptr)
			enumValueDesc = ei.(enumx.IEnum[uint64]).GetDesc(v)
			break
		case reflect.Float32:
			v := *(*float32)(ptr)
			enumValueDesc = ei.(enumx.IEnum[float32]).GetDesc(v)
			break
		case reflect.Float64:
			v := *(*float64)(ptr)
			enumValueDesc = ei.(enumx.IEnum[float64]).GetDesc(v)
			break

		case reflect.Complex64:
			v := *(*complex64)(ptr)
			enumValueDesc = ei.(enumx.IEnum[complex64]).GetDesc(v)
			break
		case reflect.Complex128:
			v := *(*complex128)(ptr)
			enumValueDesc = ei.(enumx.IEnum[complex128]).GetDesc(v)
			break
		}

		stream.WriteRaw(enumValueDesc)
		stream.WriteRaw("\"")

	}

}

func NewEnumEncoder(enumName string, encoder0 jsoniter.ValEncoder, binding *jsoniter.Binding, descFieldNameSubffix string) *EnumEncoder {
	return &EnumEncoder{enumName: enumName, encoder0: encoder0, binding: binding, descFieldNameSubffix: descFieldNameSubffix}
}

type UpdateStructEnumFieldDescriptorExtension struct {
	jsoniter.DummyExtension
	descFieldNameSubffix string // 枚举描述字段的后缀，转json时候除写入原字段外还写入一个新字段，新字段名称=原字段名称+后缀
}

func (extension *UpdateStructEnumFieldDescriptorExtension) UpdateStructDescriptor(structDescriptor *jsoniter.StructDescriptor) {
	// 获取结构体标签注册解析
	for _, binding := range structDescriptor.Fields {
		enumName := binding.Field.Tag().Get(tagx.EnumTagName)
		if "" == enumName {
			continue
		}
		binding.Encoder = NewEnumEncoder(enumName, binding.Encoder, binding, extension.descFieldNameSubffix)
	}

}

func NewUpdateStructEnumFieldDescriptorExtension(descFieldNameSubffix string) *UpdateStructEnumFieldDescriptorExtension {
	return &UpdateStructEnumFieldDescriptorExtension{
		descFieldNameSubffix: descFieldNameSubffix,
	}
}
